﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using DimensionsHelper.Common.Contracts.DataCollector;
using DimensionsHelper.Common.Contracts.DataCollector.Options;
using DimensionsHelper.Common.Contracts.Excel;
using DimensionsHelper.Common.Contracts.Services;
using DimensionsHelper.Common.Utils;
using DimensionsHelper.Services.DataCollector.Options;

namespace DimensionsHelper.Services.DataCollector;

public class ExcelDataCollector : ICollector
{
    private readonly OptionHelper _optionHelper;
    private readonly Validator _validator;

    private IReportService? _reportService;

    private IExcelReader _reader;
    private IExcelWriter _writer;

    public string Section => "Collector";


    public ExcelDataCollector(CollectorOptions options, IReportService? reportService)
    {
        _reportService = reportService;

        _validator = new Validator
        {
            ReportService = reportService
        };
        _optionHelper = new OptionHelper(options, _validator);

        _reader = new ExcelDataTreeReader(reportService);
        _reader.SetOptions(_optionHelper);

        _writer = new ExcelAggregateWriter(reportService);
        _writer.SetOptions(_optionHelper);
    }

    public ExcelDataCollector() : this(new CollectorOptions(), null)
    {
    }

    public IFilePikerService? FilePikerService { get; set; }
        
    public IReportService? ReportService
    {
        get => _reportService;

        set
        {
            if (_reportService == value)
            {
                return;
            }

            _reportService = value;
            _validator.ReportService = value;
            _reader.ReportService = value;
            _writer.ReportService = value;
        }
    }

    public CollectorOptions Settings => _optionHelper.Options;


    public IExcelReader Reader
    {
        get => _reader;

        set
        {
            _reader.ReportService = null;
            _reader = value;
            _reader.ReportService = ReportService;
            _reader.SetOptions(_optionHelper);
        }
    }


    public IExcelWriter Writer
    {
        get => _writer;

        set
        {
            _writer.ReportService = null;
            _writer = value;
            _writer.ReportService = ReportService;
            _writer.SetOptions(_optionHelper);
        }
    }


    public bool LoadSettings(CollectorOptions options)
    {
        _optionHelper.SetOptions(options);
        return _optionHelper.IsInitialized;
    }


    public bool LoadSettings(object obj)
    {
        if (obj is CollectorOptions options)
        {
            return LoadSettings(options);
        }

        return false;
    }


    public bool LoadSettings(string jsonFileName)
    {
        try
        {
            var jsonObj = JsonHelper.ReadJson(jsonFileName, ServiceJsonContext.Default.CollectorOptions);

            if (jsonObj != null)
            {
                _optionHelper.SetOptions(jsonObj);
                return true;
            }

            ReportService?.Error($"配置文件'{jsonFileName}'转换配置对象时失败。");
        }
        catch (Exception ex)
        {
            ReportService?.Error(ex.Message);
        }

        return false;
    }

    public void Collect(IEnumerable<CollectorInputFile> files)
    {
        Collect(files, CancellationToken.None);
    }

    public void Collect(IEnumerable<CollectorInputFile> files, CancellationToken cancellationToken)
    {
        _reader.Clear();

        foreach (var file in files)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }

            try
            {
                file.Operator.Open(file.FileName);
                _reader.ReadExcel(file.Operator, file.Index, file.Expression, cancellationToken);
            }
            catch (Exception e)
            {
                ReportService?.Error(e.Message);
            }
            finally
            {
                file.Operator.Close();
            }
        }
    }

    public void Export(IExcelWorkbookOperator workbook)
    {
        Export(workbook, CancellationToken.None);
    }

    public void Export(IExcelWorkbookOperator workbook, CancellationToken cancellationToken)
    {
        var data = _reader.GetData<ExcelDataNode>();

        if (data.ChildCount == 0)
        {
            ReportService?.Error("当前已读取数据为空。");
            return;
        }

        Writer.WriteToExcel(workbook, data, cancellationToken);

        ReportService?.Directory(Path.GetDirectoryName(workbook.FileName) ?? "", "输出结果目标文件夹");
        ReportService?.Directory(workbook.FileName, "输出结果目标文件");
    }


    public void Clear()
    {
        _reader.Clear();
    }
}